package com.ruoyi.attendance.service.impl;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.attendance.domain.AttendancePolicies;
import com.ruoyi.attendance.dto.AttendanceRecordQueryDTO;
import com.ruoyi.attendance.entity.EmployeeInfo;
import com.ruoyi.attendance.entity.ScheduleManagement;
import com.ruoyi.attendance.entity.WorkTimePeriod;
import com.ruoyi.attendance.mapper.AttendancePoliciesMapper;
import com.ruoyi.attendance.utils.DateRangeCalculator;
import com.ruoyi.attendance.vo.AttendanceRecordVo;
import com.ruoyi.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.attendance.mapper.AttendanceRecordMapper;
import com.ruoyi.attendance.domain.AttendanceRecord;
import com.ruoyi.attendance.service.IAttendanceRecordService;

import javax.accessibility.AccessibleText;

/**
 * 员工考勤记录Service业务层处理
 * 
 * @author ruoyi
 * @date 2025-06-05
 */
@Slf4j
@Service
public class AttendanceRecordServiceImpl implements IAttendanceRecordService 
{
    @Autowired
    private AttendanceRecordMapper attendanceRecordMapper;
    @Autowired
    private ScheduleServiceImpl scheduleService;
    @Autowired
    private AttendancePoliciesMapper attendancePoliciesMapper;

    /**
     * 查询员工考勤记录
     * 
     * @param id 员工考勤记录主键
     * @return 员工考勤记录
     */
    @Override
    public AttendanceRecord selectAttendanceRecordById(Integer id)
    {
        return attendanceRecordMapper.selectAttendanceRecordById(id);
    }

    /**
     * 查询员工考勤记录列表
     * 
     * @param attendanceRecord 员工考勤记录
     * @return 员工考勤记录
     */
    @Override
    public List<AttendanceRecord> selectAttendanceRecordList(AttendanceRecord attendanceRecord)
    {
        return attendanceRecordMapper.selectAttendanceRecordList(attendanceRecord);
    }

    /**
     * 新增员工考勤记录
     * 
     * @param attendanceRecord 员工考勤记录
     * @return 结果
     */
    // @Override
    // public int insertAttendanceRecord(AttendanceRecord attendanceRecord)
    // {
    //
    //     // 设置一个标记字段, 用于标记是插入还是更新
    //     boolean isInsert = true;
    //     // 标记是否需要计算额外属性
    //     boolean isNeedCalculateExtraProperties = false;
    //
    //     // 根据用户id获取用户个人信息
    //     EmployeeInfo employeeInfo = attendanceRecordMapper.selectEmployeeInfoById(attendanceRecord.getUserId());
    //
    //     log.info("根据用户id获取用户个人信息:{}",employeeInfo);
    //     // 将获取的用户个人信息设置到考勤记录中
    //     attendanceRecord.setUserName(employeeInfo.getUserName());
    //     attendanceRecord.setDepartmentName(employeeInfo.getDepartmentName());
    //     attendanceRecord.setPositionName(employeeInfo.getPositionName());
    //     attendanceRecord.setDeptId(employeeInfo.getDeptId());
    //
    //
    //     // 需要根据用户id和考勤日期获取该员工的排班计划
    //     // 1. 获取该员工的排班计划
    //     ScheduleManagement scheduleManagement = scheduleService.getScheduleManagementByIdAndDate(attendanceRecord.getUserId(), attendanceRecord.getRecordDate());
    //     log.info("获取用户id{}的排班计划为:{}",attendanceRecord.getUserId(), scheduleManagement);
    //     if (scheduleManagement == null) {
    //         // 无排班计划, 今日打卡不计算额外属性
    //         log.info("无排班计划, 今日打卡不计算额外属性");
    //     }else {
    //         // 有排班计划, 计算额外属性
    //         log.info("有排班计划, 准备计算额外属性");
    //         // 先查询是否有考勤规则
    //         AttendancePolicies attendancePolicies = attendancePoliciesMapper.selectAttendancePoliciesById(Long.valueOf(scheduleManagement.getAttendancePoliciesId()));
    //
    //         log.info("查询到考勤规则为:{}",attendancePolicies);
    //         if (attendancePolicies == null) {
    //             // 无考勤规则, 今日打卡不计算额外属性
    //             log.info("无考勤规则, 今日打卡不计算额外属");
    //         }else {
    //             // 有考勤规则, 计算额外属性
    //             log.info("有考勤规则, 准备计算额外属性");
    //             isNeedCalculateExtraProperties = true;
    //         }
    //     }
    //
    //     // 2. 获取该员工的排班计划中详细的上班时间和下班时间等信息
    //     // 插入考勤记录逻辑
    //     // 检查是否存在相同的用户ID和日期记录
    //     AttendanceRecord existingRecord = attendanceRecordMapper.selectAttendanceRecordByUserIdAndDate(attendanceRecord.getUserId(), attendanceRecord.getRecordDate());
    //
    //
    //     if (existingRecord == null) {
    //         // 无记录, 可以插入新记录, 代表本次是上班打卡
    //         log.info("无记录, 可以插入新记录, 代表本次是上班打卡");
    //     }else {
    //         // 有记录, 代表是下班打卡, 可以更新记录
    //        log.info("有记录, 代表是下班打卡, 可以更新记录");
    //         isInsert = false;
    //         existingRecord.setClockOutTime(attendanceRecord.getClockOutTime());
    //         // 检查是否是下班打卡
    //     }
    //
    //     if (isInsert) {
    //         // 插入考勤记录
    //         log.info("插入考勤记录");
    //         return attendanceRecordMapper.insertAttendanceRecord(attendanceRecord);
    //     }else {
    //         // 更新考勤记录
    //         log.info("更新考勤记录");
    //         return attendanceRecordMapper.updateAttendanceRecord(existingRecord);
    //     }
    // }

    /**
     * 修改员工考勤记录
     * 
     * @param attendanceRecord 员工考勤记录
     * @return 结果
     */
    @Override
    public int updateAttendanceRecord(AttendanceRecord attendanceRecord)
    {
        return attendanceRecordMapper.updateAttendanceRecord(attendanceRecord);
    }

    /**
     * 批量删除员工考勤记录
     * 
     * @param ids 需要删除的员工考勤记录主键
     * @return 结果
     */
    @Override
    public int deleteAttendanceRecordByIds(Integer[] ids)
    {
        return attendanceRecordMapper.deleteAttendanceRecordByIds(ids);
    }

    /**
     * 删除员工考勤记录信息
     * 
     * @param id 员工考勤记录主键
     * @return 结果
     */
    @Override
    public int deleteAttendanceRecordById(Integer id)
    {
        return attendanceRecordMapper.deleteAttendanceRecordById(id);
    }

    @Override
    public AttendanceRecordVo getSummary(AttendanceRecordQueryDTO recordQueryDTO) {

        // 先将查询条件转换为日期
        Date[] dates = DateRangeCalculator.calculateDateRange(recordQueryDTO.getYear(), recordQueryDTO.getMonth());
        Date startDate = dates[0];
        Date endDate = dates[1];
        // 查询员工的考勤记录
        List<AttendanceRecord> records = attendanceRecordMapper.selectAttendanceRecordByUserIdAndDateRange(recordQueryDTO.getUserId(), startDate, endDate);

        log.info("查询到的考勤记录为: {}", records);

        // 记录实际出勤天数
        AttendanceRecordVo attendanceRecordVo = new AttendanceRecordVo();
        attendanceRecordVo.setActualAttendanceDays(records.size());

        // 查询员工的排班计划, 只需要统计计数政策id不为0的记录
        Integer actualAttendanceDays =  attendanceRecordMapper.selectActualAttendanceDaysByUserIdAndDateRange(recordQueryDTO.getUserId(), startDate, endDate);

        log.info("查询到的应出勤天数为: {}", actualAttendanceDays);
        // 设置应出勤天数
        attendanceRecordVo.setShouldAttendanceDays(actualAttendanceDays);

        // 计算其他属性
        if (records.isEmpty()) {
            throw new RuntimeException("没有考勤记录, 无法计算其他属性");
        }
        // 计算迟到次数和早退次数, 加班次数和加班总时长
        int lateTimes = 0; // 早退
        int earlyLeaveTimes = 0; // 迟到
        int overtimeTimes = 0; // 加班次数
        BigDecimal overtimeTotalHours = BigDecimal.ZERO; // 加班总时长
        for (AttendanceRecord record : records) {
            if (record.getEarlyRecordStatus() == 2) {
                earlyLeaveTimes++;
            }
            if (record.getLateRecordStatus() == 2) {
                lateTimes++;
            }
            if (record.getOvertimeRecordStatus() == 1) {
                overtimeTimes++;
                overtimeTotalHours = overtimeTotalHours.add(record.getOvertimeHours());
            }
        }
        attendanceRecordVo.setLateTimes(earlyLeaveTimes);
        attendanceRecordVo.setEarlyLeaveTimes(lateTimes);
        attendanceRecordVo.setOvertimeTimes(overtimeTimes);
        attendanceRecordVo.setOvertimeTotalHours(overtimeTotalHours);


        return attendanceRecordVo;
    }


    @Override
    public int insertAttendanceRecord(AttendanceRecord attendanceRecord) {
        // 1. 加载用户基本信息
        EmployeeInfo employeeInfo = loadEmployeeInfo(attendanceRecord.getUserId());
        fillEmployeeInfoToRecord(attendanceRecord, employeeInfo);

        // 2. 检查排班计划和考勤规则
        ScheduleManagement schedule = loadSchedule(attendanceRecord.getUserId(), attendanceRecord.getRecordDate());
        AttendancePolicies policies = loadAttendancePolicies(schedule);

        // 3. 解析考勤政策中的工作时间段
        List<WorkTimePeriod> workPeriods = parseWorkTimePeriods(policies);
        log.info("解析考勤政策工作时间段结果: {}", workPeriods);

        // 4. 检查是否已有考勤记录
        AttendanceRecord existingRecord = findExistingRecord(attendanceRecord);

        // 5. 根据是否存在记录决定是插入还是更新
        if (existingRecord == null) {
            log.info("创建新考勤记录: 上班打卡");
            prepareForInsert(attendanceRecord, schedule, policies, workPeriods);
            return attendanceRecordMapper.insertAttendanceRecord(attendanceRecord);
        } else {
            log.info("更新现有考勤记录: 下班打卡");
            prepareForUpdate(existingRecord, attendanceRecord, schedule, policies, workPeriods);
            return attendanceRecordMapper.updateAttendanceRecord(existingRecord);
        }
    }

    // 获取用户的排班计划
    private ScheduleManagement loadSchedule(Integer userId, Date recordDate) {
        ScheduleManagement schedule = scheduleService.getScheduleManagementByIdAndDate(userId, recordDate);
        log.info("获取用户id{}的排班计划为: {}", userId, schedule);
        return schedule;
    }

    // 获取考勤规则
    private AttendancePolicies loadAttendancePolicies(ScheduleManagement schedule) {
        if (schedule == null) {
            log.info("无排班计划, 今日打卡不计算额外属性");
            return null;
        }

        AttendancePolicies policies = attendancePoliciesMapper.selectAttendancePoliciesById(
                Long.valueOf(schedule.getAttendancePoliciesId()));

        log.info("查询到考勤规则为: {}", policies);
        return policies;
    }

    // 检查是否存在相同的用户ID和日期记录
    private AttendanceRecord findExistingRecord(AttendanceRecord record) {
        return attendanceRecordMapper.selectAttendanceRecordByUserIdAndDate(
                record.getUserId(), record.getRecordDate());
    }

    // 填充员工信息到考勤记录
    private void fillEmployeeInfoToRecord(AttendanceRecord record, EmployeeInfo info) {
        record.setUserName(info.getUserName());
        record.setDepartmentName(info.getDepartmentName());
        record.setPositionName(info.getPositionName());
        record.setDeptId(info.getDeptId());
    }

    // 加载用户基本信息
    private EmployeeInfo loadEmployeeInfo(Integer userId) {
        EmployeeInfo employeeInfo = attendanceRecordMapper.selectEmployeeInfoById(userId);
        log.info("根据用户id获取用户个人信息: {}", employeeInfo);
        return employeeInfo;
    }

    // 解析考勤政策中的工作时间段
    private List<WorkTimePeriod> parseWorkTimePeriods(AttendancePolicies policies) {
        List<WorkTimePeriod> periods = new ArrayList<>();
        if (policies == null || StringUtils.isEmpty(policies.getWorkTimeJson())) {
            return periods;
        }
        try {
            // 解析JSON字符串
            JSONArray jsonArray = JSONArray.parseArray(policies.getWorkTimeJson());
            for (int i = 0; i < jsonArray.size(); i++) {
                JSONObject periodObj = jsonArray.getJSONObject(i);
                String startStr = periodObj.getString("start");
                String endStr = periodObj.getString("end");

                // 转换为LocalTime
                LocalTime startTime = LocalTime.parse(startStr);
                LocalTime endTime = LocalTime.parse(endStr);

                periods.add(new WorkTimePeriod(startTime, endTime));
            }
        } catch (Exception e) {
            log.error("解析考勤政策工作时间段失败: {}", e.getMessage());
        }

        return periods;
    }



    // 处理上班打卡的额外属性计算 OK
    private void prepareForInsert(AttendanceRecord record,ScheduleManagement schedule, AttendancePolicies policies,List<WorkTimePeriod> workPeriods) {
        if (policies == null || workPeriods.isEmpty()) {
            return;
        }

        // 假设只处理第一个工作时间段（简化逻辑）
        WorkTimePeriod firstPeriod = workPeriods.get(0);

        // 计算上班相关属性
        if (record.getClockInTime() != null) {
            // 检查是否迟到
            boolean isLate = checkIsLate(record.getClockInTime(), firstPeriod, policies.getTolerateTimes().intValue());
            record.setEarlyRecordStatus(isLate ? 2 : 1);
            log.info("早上打卡是否迟到: {}", isLate);

            // // 计算实际工作时长（如果下班时间也存在）
            // if (record.getClockOutTime() != null) {
            //     calculateWorkHours(record, workPeriods, policies);
            // }
        }
    }

    // 处理下班打卡的额外属性计算
    private void prepareForUpdate(AttendanceRecord existingRecord,AttendanceRecord newRecord,ScheduleManagement schedule,AttendancePolicies policies,List<WorkTimePeriod> workPeriods) {
        // 设置下班时间
        existingRecord.setClockOutTime(newRecord.getClockOutTime());

        if (policies == null || workPeriods.isEmpty()) {
            return;
        }

        // 假设只处理第一个工作时间段（简化逻辑）
        WorkTimePeriod firstPeriod = workPeriods.get(0);

        // 计算下班相关属性
        if (existingRecord.getClockOutTime() != null) {
            // 检查是否早退
            boolean isEarly = checkIsEarly(existingRecord.getClockOutTime(), firstPeriod, policies.getTolerateTimes().intValue());
            existingRecord.setLateRecordStatus(isEarly ? 2 : 1);
            log.info("下班打卡是否早退: {}", isEarly);

            // 计算实际工作时长
            if (existingRecord.getClockInTime() != null) {
                calculateWorkHours(existingRecord, workPeriods, policies);
            }

            // 计算加班时长
            if (existingRecord.getActualWorkHours() != null) {
                calculateOvertime(existingRecord, workPeriods, policies);
            }
            // 如果计算的加班时长大于0，设置加班状态为1
            int i = existingRecord.getOvertimeHours().compareTo(BigDecimal.valueOf(0));
            existingRecord.setOvertimeRecordStatus(i > 0 ? 1 : 2);
        }
    }

    // 检查是否迟到
    private boolean checkIsLate(Date clockInTime, WorkTimePeriod period, int tolerateMinutes) {
        LocalTime clockInLocalTime = clockInTime.toInstant().atZone(ZoneId.systemDefault()).toLocalTime();

        // 允许的最晚打卡时间 = 上班时间 + 容忍分钟
        LocalTime latestAllowedTime = period.getStartTime().plusMinutes(tolerateMinutes);

        return clockInLocalTime.isAfter(latestAllowedTime);
    }

    // 检查是否早退 OK
    private boolean checkIsEarly(Date clockOutTime, WorkTimePeriod period, int tolerateMinutes) {
        LocalTime clockOutLocalTime = clockOutTime.toInstant().atZone(ZoneId.systemDefault()).toLocalTime();

        // 允许的最早打卡时间 = 下班时间 - 容忍分钟
        LocalTime earliestAllowedTime = period.getEndTime().minusMinutes(tolerateMinutes);

        return clockOutLocalTime.isBefore(earliestAllowedTime);
    }

    // 计算工作时长
    private void calculateWorkHours00(AttendanceRecord record,List<WorkTimePeriod> workPeriods,AttendancePolicies policies) {
        if (record.getClockInTime() == null || record.getClockOutTime() == null) {
            return;
        }

        // 转换打卡时间为LocalDateTime
        LocalDateTime clockIn = record.getClockInTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();

        LocalDateTime clockOut = record.getClockOutTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();

        // 计算实际工作时长（考虑多个时间段）
        double actualHours = 0;
        for (WorkTimePeriod period : workPeriods) {
            // 计算该时间段的工作时长
            LocalDateTime periodStart = LocalDateTime.of(clockIn.toLocalDate(), period.getStartTime());
            LocalDateTime periodEnd = LocalDateTime.of(clockIn.toLocalDate(), period.getEndTime());

            // 处理跨天的情况（如夜班）
            if (periodEnd.isBefore(periodStart)) {
                periodEnd = periodEnd.plusDays(1);
            }

            // 计算交集
            LocalDateTime effectiveStart = clockIn.isAfter(periodStart) ? clockIn : periodStart;
            LocalDateTime effectiveEnd = clockOut.isBefore(periodEnd) ? clockOut : periodEnd;

            // 如果有交集，计算时长
            if (effectiveEnd.isAfter(effectiveStart)) {
                long diffInSeconds = Duration.between(effectiveStart, effectiveEnd).getSeconds();
                actualHours += diffInSeconds / 3600.0;
            }
        }

        record.setActualWorkHours(BigDecimal.valueOf(actualHours));
        record.setRequiredWorkHours(policies.getWorkHoursPerDay());

        log.info("计算工作时长: 实际={}小时, 应工作={}小时", actualHours, policies.getWorkHoursPerDay());
    }

    // 计算工作时长（保留原有参数，简化计算逻辑）
    private void calculateWorkHours(AttendanceRecord record,
                                    List<WorkTimePeriod> workPeriods,
                                    AttendancePolicies policies) {
        if (record.getClockInTime() == null || record.getClockOutTime() == null) {
            log.info("缺少上班或下班时间，无法计算工作时长");
            return;
        }

        log.info("开始计算工作时长: 上班时间={}, 下班时间={}",
                record.getClockInTime(), record.getClockOutTime());

        // 直接计算上下班时间差（不考虑时间段配置）
        long diffInMillis = record.getClockOutTime().getTime() - record.getClockInTime().getTime();

        // 转换为小时（保留两位小数）
        BigDecimal actualHours = BigDecimal.valueOf(diffInMillis).divide(BigDecimal.valueOf(1000 * 60 * 60), 2, RoundingMode.HALF_UP);

        // 政策中一般都是休息2小时，所以实际工作时长应该减去2小时
        actualHours = actualHours.subtract(BigDecimal.valueOf(2));

        // 如果实际工作时长小于0，重置为0
        if (actualHours.compareTo(BigDecimal.ZERO) < 0) {
            actualHours = BigDecimal.ZERO;
        }

        // 设置实际工作时长和应工作时长
        record.setActualWorkHours(actualHours);
        record.setRequiredWorkHours(policies.getWorkHoursPerDay());

        log.info("计算工作时长完成: 实际={}小时, 应工作={}小时",actualHours, policies.getWorkHoursPerDay());
    }

    // 计算加班时长
    private void calculateOvertime(AttendanceRecord record,List<WorkTimePeriod> workPeriods,AttendancePolicies policies) {
        if (record.getActualWorkHours() == null || workPeriods.isEmpty()) {
            return;
        }

        // 假设只考虑最后一个时间段的结束时间作为加班计算起点（简化逻辑）
        WorkTimePeriod lastPeriod = workPeriods.get(workPeriods.size() - 1);

        // 转换打卡时间为LocalDateTime
        LocalDateTime clockOut = record.getClockOutTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();

        // 加班起始时间 = 下班时间 + 加班起始分钟
        LocalDateTime overtimeStart = LocalDateTime.of(
                clockOut.toLocalDate(),
                lastPeriod.getEndTime()
        ).plusMinutes(policies.getOvertimeStart());

        // 处理跨天的情况
        if (overtimeStart.isBefore(clockOut.toLocalDate().atStartOfDay())) {
            overtimeStart = overtimeStart.plusDays(1);
        }

        // 如果打卡时间晚于加班起始时间，计算加班时长
        double overtimeHours = 0;
        if (clockOut.isAfter(overtimeStart)) {
            long diffInSeconds = Duration.between(overtimeStart, clockOut).getSeconds();
            overtimeHours = diffInSeconds / 3600.0;
        }

        record.setOvertimeHours(BigDecimal.valueOf(overtimeHours));
        log.info("计算加班时长: {}小时", overtimeHours);

    }


}
